package utils;

import java.util.*;

public class BBList<E> implements Iterable<E> {
    private BBNode headNode;
    private BBNode tailNode;

    public BBList() {
        this.headNode = null;
        this.tailNode = null;
    }

    public void insertHead(E element) {
        BBNode newNode = new BBNode(element, headNode, null);
        if (headNode != null) {
            headNode.prev = newNode;
        }
        headNode = newNode;
        if (tailNode == null) {
            tailNode = newNode;
        }
    }

    public void insertTail(E element) {
        BBNode newNode = new BBNode(element, null, tailNode);
        if (tailNode != null) {
            tailNode.next = newNode;
        }
        tailNode = newNode;
        if (headNode == null) {
            headNode = newNode;
        }
    }

    public E getHead() {
        return headNode.get();
    }

    public E getTail() {
        return tailNode.get();
    }

    public BBNode getHeadNode() {
        return headNode;
    }

    public BBNode getTailNode() {
        return tailNode;
    }

    @Override
    public Iterator<E> iterator() {
        return new BBIterator(headNode);
    }

    class BBIterator implements Iterator<E> {
        private BBNode current;
        private BBIterator(BBNode head) {
            this.current = head;
        }
        @Override
        public boolean hasNext() {
            return current != null;
        }
        @Override
        public E next() {
            E value = current.element;
            current = current.next;
            return value;
        }
    }

    public class BBNode {
        protected E element;
        protected BBNode next;
        protected BBNode prev;
        protected BBNode(E element) {
            this.element = element;
        }
        protected BBNode(E element, BBNode next, BBNode prev) {
            this.element = element;
            this.next = next;
            this.prev = prev;
        }

        public BBNode(BBNode bbNode) {
            this.element = bbNode.element;
            this.next = bbNode.next;
            this.prev = bbNode.prev;
        }

        public E get() {
            return element;
        }

        public void set(E element) {
            this.element = element;
        }

        public BBNode getNextNode() {
            return next;
        }

        public BBNode getPrevNode() {
            return prev;
        }

        public void insertBefore(E element) {
            BBNode newNode = new BBNode(element, this, this.prev);
            if (this.prev != null) {
                this.prev.next = newNode;
            }
            else {
                headNode = newNode;
            }
            this.prev = newNode;
        }

        public void insertAfter(E element){
            BBNode newNode = new BBNode(element, this.next, this);
            if (this.next != null) {
                this.next.prev = newNode;
            }
            else {
                tailNode = newNode;
            }
            this.next = newNode;
        }
    }
}




